/** * Java Diagram Package; An extremely flexible and fast multipurpose diagram component for Swing. Copyright (C) 2001 Eric Crahen <crahen@cse.buffalo.edu> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package diagram.tool; import java.awt.event.ActionEvent; import java.lang.ref.WeakReference; import java.util.ArrayList; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import diagram.Diagram; import diagram.DiagramModel; import diagram.DiagramUI; import diagram.Figure; import diagram.Link; import diagram.SelectionModel; /** * @class ClipboardTool * * @date 08-20-2001 * @author Eric Crahen * @version 1.0 * * A Clipboard implements the copy/cut/paste actions for a Diagram. * A set of actions are inserted into the target Diagrams ActionMap * (copy, cut, and paste) that allow the UI to map inputs to these * actions as it sees fit. */ public class ClipboardTool extends AbstractTool { // This implementation shares a single instance of a clipboard across all // threads and uses a ThreadLocal to different between requests protected static ThreadLocal diagramKey = new InheritableThreadLocal(); protected Action actionCut = new CutAction(); protected Action actionCopy = new CopyAction(); protected Action actionPaste = new PasteAction(); private Figure[] figures = new Figure[4]; private Figure[] related = new Figure[4]; private ArrayList clipboard = new ArrayList(); private ArrayList copyboard = new ArrayList(); /** * Install the support in the specified Diagram * * @param Diagram */ public void install(Diagram diagram) { ActionMap map = diagram.getActionMap(); map.put("cut", actionCut); map.put("copy", actionCopy); map.put("paste", actionPaste); setDiagram(diagram); } /** * Install the support in the specified Diagram * * @param Diagram */ public void uninstall(Diagram diagram) { ActionMap map = diagram.getActionMap(); map.remove("cut"); map.remove("copy"); map.remove("paste"); setDiagram(null); } /** * Configure the current context for the given Diagram * * @param Diagram * @return Clipboard */ static public void setDiagram(Diagram diagram) { if(getDiagram() != diagram) diagramKey.set(new WeakReference(diagram)); } /** * Get the diagram the Clipboard is configured for * * @return Diagram */ static public Diagram getDiagram() { Object o = diagramKey.get(); if(o != null) o = ((WeakReference)o).get(); return (Diagram)o; } /** * Prepare for a clipboard operation. Copy the current selection into a local array * for processing. * * @return boolean */ protected boolean prepareSelection() { // Get the correct diagram Diagram diagram = getDiagram(); if(diagram == null) return false; // Get the selected figures SelectionModel selectionModel = diagram.getSelectionModel(); if(selectionModel == null) return false; figures = (Figure[])selectionModel.toArray(figures); return true; } /** * Copy the current selection from the Diagram to the Clipboard */ public void doCopy() { if(!prepareSelection()) return; synchronized(figures) { // Clone the copied figures into a Vector for later processing clipboard.clear(); for(int i=0; i<figures.length && figures[i] != null; i++) { Figure figure = figures[i]; clipboard.add(figure); } } } /** * Cut the current selection from the Diagram */ public void doCut() { if(!prepareSelection()) return; DiagramModel model = getDiagram().getModel(); DiagramUI ui = (DiagramUI)getDiagram().getUI(); // Walk through the selected items Figure figure = null; for(int i=0; i<figures.length && figures[i] != null; i++) { figure = figures[i]; // Cut related items first (usually links) related = ui.getConnected(figure, related); for(int j=0; j<related.length && related[j] != null; j++) { model.remove(related[j]); ui.damageFigure(related[j]); } // Cut the selected item model.remove(figure); ui.damageFigure(figure); } // Refresh ui.refreshFigure(figure); } /** * Paste the top of the clipboard stack to the diagram */ public void doPaste() { // Get the correct diagram Diagram diagram = getDiagram(); if(diagram == null) return; // Get the selected figures SelectionModel selectionModel = diagram.getSelectionModel(); if(selectionModel == null) return; if(clipboard.isEmpty()) return; DiagramModel model = getDiagram().getModel(); DiagramUI ui = (DiagramUI)getDiagram().getUI(); Figure figure = null; // Paste all link figures next, only if both the sink & source for the // link were also pasted copyboard.addAll(clipboard); clipboard.clear(); // Clear current selection, add the pasted figures selectionModel.clear(); // Copy all linked items for(int i=0; i<copyboard.size(); i++) { // Skip nulls (from being pasted w/ thier links) Figure f = (Figure)copyboard.get(i); if(f == null) continue; // Rember last good figure for refresh at the end figure = f; ui.damageFigure(figure); if(figure instanceof Link) { Link link = (Link)figure; int index; // Check the sink Figure sink = link.getSink(); if(sink != null && (index = copyboard.indexOf(sink)) != -1) { sink = (Figure)sink.clone(); // Paste the sink doPaste(sink, model, selectionModel, ui); copyboard.set(index, null); // Check the source Figure source = link.getSource(); if(source != null && (index = copyboard.indexOf(source)) != -1) { source = (Figure)source.clone(); // Paste the source doPaste(source, model, selectionModel, ui); copyboard.set(index, null); // Clone the link & paste it System.err.println( link.equals(link.clone())); link = (Link)link.clone(); link.setSink(sink); link.setSource(source); doPaste(link, model, selectionModel, ui); copyboard.set(i, null); } } } } // Copy all non-linked items for(int i=0; i<copyboard.size(); i++) { // Skip nulls (from being pasted w/ thier links) Figure f = (Figure)copyboard.get(i); if(f != null) { ui.damageFigure(f); figure = (Figure)f.clone(); doPaste(figure, model, selectionModel, ui); } } copyboard.clear(); // Refresh diagram ui.refreshFigure(figure); } /** * */ private final void doPaste(Figure figure, DiagramModel model, SelectionModel selectionModel, DiagramUI ui) { figure.translate(10,10); model.add(figure); selectionModel.add(figure); clipboard.add(figure); ui.damageFigure(figure); } /** * @class CutAction * */ protected class CutAction extends AbstractAction { public CutAction() { super("Cut"); } public void actionPerformed(ActionEvent e) { doCut(); } } /** * @class CopyAction * */ protected class CopyAction extends AbstractAction { public CopyAction() { super("Copy"); } public void actionPerformed(ActionEvent e) { doCopy(); } } /** * @class PasteAction * */ protected class PasteAction extends AbstractAction { public PasteAction() { super("Paste"); } public void actionPerformed(ActionEvent e) { doPaste(); } } }